﻿using HslCommunication.Secs;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.UI.WebControls.WebParts;
using static DataCapture.Helper.PublicHelp;

namespace DataCapture.Helper;

public class PropertySetter<T>
{
    private readonly ConcurrentDictionary<Type, IDictionary<string, Action<T, object>>> _cache= new ConcurrentDictionary<Type, IDictionary<string, Action<T, object>>>();


        public PropertySetter(ElementConfig elementConfig)  
    {
        foreach (ModuleConfig config in elementConfig.ModuleConfig)
        {
            foreach (PlcPart part in config.PartList)
            {
                AddMapping(part.PartType, part.PartType);
            }
        }
        _mapperFunc = BuildMapper();
    }

    private  IDictionary<string, Action<T, object>> BuildFieldActions(Type entityType)
    {
        var result = new Dictionary<string, Action<T, object>>();

        // 处理字段
        foreach (var field in entityType.GetFields(BindingFlags.Public | BindingFlags.Instance))
        {
            var setAction = CreateFieldSetter(entityType, field);
            result[field.Name] = setAction;
        }

        // 处理属性
        foreach (var property in entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            if (property.CanWrite)
            {
                var setAction = CreatePropertySetter(entityType, property);
                result[property.Name] = setAction;
            }
        }

        return result;
    }
    /// <summary>
    /// 创建字段设置方法
    /// </summary>
    /// <param name="entityType"></param>
    /// <param name="field"></param>
    /// <returns></returns>
    private  Action<T, object> CreateFieldSetter(Type entityType, FieldInfo field)
    {
        var entityParam = Expression.Parameter(entityType, "entity");
        var valueParam = Expression.Parameter(typeof(object), "value");
        var fieldValue = Expression.Field(entityParam, field);
        var convertedValue = Expression.Convert(valueParam, field.FieldType);

        var assign = Expression.Assign(fieldValue, convertedValue);
        var lambda = Expression.Lambda<Action<T, object>>(
            assign,
            entityParam,
            valueParam
        );

        return lambda.Compile();
    }
    /// <summary>
    /// 创建属性的设置方法
    /// </summary>
    /// <param name="entityType"></param>
    /// <param name="property"></param>
    /// <returns></returns>
    private  Action<T, object> CreatePropertySetter(Type entityType, PropertyInfo property)
    {
        var entityParam = Expression.Parameter(entityType, "entity");
        var valueParam = Expression.Parameter(typeof(object), "value");
        var propertyExpr = Expression.Property(entityParam, property);
        var convertedValue = Expression.Convert(valueParam, property.PropertyType);

        var assign = Expression.Assign(propertyExpr, convertedValue);
        var lambda = Expression.Lambda<Action<T, object>>(
            assign,
            entityParam,
            valueParam
        );

        return lambda.Compile();
    }
    /// <summary>
    /// 设置属性值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entity"></param>
    /// <param name="propertyName"></param>
    /// <param name="value"></param>
    public  void SetPropertyValue(T entity, string propertyName, object value)
    {
        var entityType = typeof(T);
        var fieldActions = _cache.GetOrAdd(entityType, BuildFieldActions);

        if (fieldActions.TryGetValue(propertyName, out var action))
        {
            action(entity, value);
        }
    }

    // 获取单个字段的赋值委托
    public  Action<T, object> GetSetter<T>(string propertyName)
    {
        var entityType = typeof(T);
        IDictionary<string, Action<T, object>> fieldActions = (IDictionary<string, Action<T, object>>)_cache.GetOrAdd(entityType, BuildFieldActions);
        if (fieldActions.TryGetValue(propertyName, out Action<T, object> action))
        {
            // 将委托类型转换为泛型安全的Action<T, object>
            return (T, value) => action(T, value);
        }
        return null;
    }

  
    // 获取所有字段的委托集合（类型安全）
    // 获取所有字段的委托集合（返回 IDictionary<string, object>）
    public  Dictionary<string, object> GetAllSetters<T>()
    {
        var entityType = typeof(T);
        var fieldActions = _cache.GetOrAdd(entityType, BuildFieldActions);
        return fieldActions
            .ToDictionary(
                kvp => kvp.Key,
                kvp => (object)kvp.Value // 将委托转换为 object 类型
            );
    }


    private   Func<Dictionary<string, object>, T> _mapperFunc;

    // 自定义字段别名（可选）
    private  readonly Dictionary<string, string> _customMappings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

    public  void AddMapping(string dictionaryKey, string propertyName)
    {
       
        _customMappings[dictionaryKey] = propertyName;

    }

    public  void ClearMappings()
    {
        _customMappings.Clear();
    }

    private  Func<Dictionary<string, object>, T> BuildMapper()
    {
        var dictType = typeof(Dictionary<string, object>);
        var itemParam = Expression.Parameter(dictType, "dict");

        var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => p.CanWrite);

        var bindings = new List<MemberBinding>();

        foreach (var prop in properties)
        {
            string propName = prop.Name;

            // 查找是否有自定义映射
            if (_customMappings.TryGetValue(propName, out var customKey))
                propName = customKey;

            var keyExpr = Expression.Constant(propName);
            var valueVar = Expression.Variable(typeof(object), "value");

            // 构造 TryGetValue 表达式
            var tryGetValueCall = Expression.Call(
                itemParam,
                typeof(Dictionary<string, object>).GetMethod("TryGetValue", new[] { typeof(string), typeof(object).MakeByRefType() }),
                keyExpr,
                valueVar
            );

            var condition = Expression.Condition(
                Expression.AndAlso(
                    Expression.Call(itemParam, typeof(Dictionary<string, object>).GetMethod("ContainsKey", new[] { typeof(string) }), keyExpr),
                    Expression.NotEqual(valueVar, Expression.Constant(null))
                ),
                ConvertValueExpression(valueVar, prop.PropertyType),
                Expression.Default(prop.PropertyType)
            );

            var binding = Expression.Bind(prop, condition);
            bindings.Add(binding);
        }

        var body = Expression.MemberInit(Expression.New(typeof(T)), bindings);
        var lambda = Expression.Lambda<Func<Dictionary<string, object>, T>>(body, itemParam);
        return lambda.Compile();
    }

    // 处理不同类型转换（包括嵌套对象）
    private  Expression ConvertValueExpression(Expression valueExp, Type targetType)
    {
        //// 如果是基本类型或字符串，直接转换
        //if (targetType.IsPrimitive || targetType == typeof(string) || targetType == typeof(object))
        //{
        //    return Expression.Convert(Expression.Property(valueExp, "ToString"), targetType);
        //}

        // 如果是另一个字典支持的实体类，递归调用 Mapper
        if (typeof(T).Assembly.GetTypes().Contains(targetType) && targetType.IsClass && targetType != typeof(string))
        {
            var method = typeof(DictionaryMapper<>).MakeGenericType(targetType)
                .GetMethod("Map", new[] { typeof(Dictionary<string, object>) });

            var parameterExp = Expression.Parameter(typeof(object), "value");
            var castedValue = Expression.Convert(parameterExp, typeof(Dictionary<string, object>));

            var callExp = Expression.Call(null, method, castedValue);

            return Expression.Convert(
                Expression.Invoke(Expression.Lambda(castedValue, parameterExp), valueExp),
                targetType
            );
        }

        // 默认尝试使用 Convert.ChangeType
        return Expression.Convert(
            Expression.Call(null, typeof(Convert).GetMethod("ChangeType", new[] { typeof(object), typeof(Type) }), valueExp, Expression.Constant(targetType)),
            targetType
        );
    }

    public  T Map(Dictionary<string, object> dict)
    {
       
        return _mapperFunc(dict);
    }
}